package com.hospital.search.module.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hospital.common.base.PageResult;
import com.hospital.common.pojo.TIndexRecord;
import com.hospital.common.utils.LocalDateTimeUtils;
import com.hospital.common.vo.search.module.IndexRecordVo;
import com.hospital.search.module.base.ActiveType;
import com.hospital.search.module.base.RollbackInfo;
import com.hospital.search.module.base.SwitchFlag;
import com.hospital.search.module.mapper.TIndexRecordMapper;
import com.hospital.search.module.service.TIndexRecordService;
import com.hospital.search.module.utils.PostIndexManager;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.Collections;
import java.util.List;

@Service
public class TIndexRecordServiceImpl extends ServiceImpl<TIndexRecordMapper, TIndexRecord> implements TIndexRecordService{
    @Autowired
    private TIndexRecordMapper tIndexRecordMapper;
    @Autowired
    private PostIndexManager postIndexManager;
    @Override
    public void insert(TIndexRecord record) {
        record.setRemark(record.getIndexName()+":"+record.getAliasName()+"->创建时间:"+LocalDateTimeUtils.format(record.getCreateTime())+"\n");
        tIndexRecordMapper.insert(record);
    }

    @Override
    public void update(String indexName,ActiveType activeType) {
        LambdaUpdateWrapper<TIndexRecord> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TIndexRecord::getIndexName, indexName)
                        .set(TIndexRecord::getIsActive, activeType.value)
                        .set(TIndexRecord::getRemark, indexName+"->修改时间:"+ LocalDateTimeUtils.nowFormatted() +"修改状态:"+activeType.name()+"\n");
        tIndexRecordMapper.update(updateWrapper);
    }

    @Override
    public Integer deleteNotActive() {
        // 保留最近一个不活跃索引,删除其他不活跃索引
        LambdaQueryWrapper<TIndexRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TIndexRecord::getIsActive, ActiveType.DEAD.value)
                .orderByDesc(TIndexRecord::getCreateTime)
                .last("limit 1");
        TIndexRecord indexRecord = tIndexRecordMapper.selectOne(queryWrapper);
        if(indexRecord==null){
            return 1;
        }
        LambdaQueryWrapper<TIndexRecord> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(TIndexRecord::getIsActive, ActiveType.DEAD.value)
                .ne(TIndexRecord::getId, indexRecord.getId());
        return tIndexRecordMapper.delete(deleteWrapper);
    }

    @Override
    @Transactional
    public RollbackInfo rollBackRecentIndex() {
        RollbackInfo rollbackInfo = new RollbackInfo();
        LambdaQueryWrapper<TIndexRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TIndexRecord::getIsActive, ActiveType.ALIVE.value);
        TIndexRecord indexRecord = tIndexRecordMapper.selectOne(queryWrapper);
        LambdaUpdateWrapper<TIndexRecord> rollback = new LambdaUpdateWrapper<>();
        LambdaUpdateWrapper<TIndexRecord> updateWrapper = new LambdaUpdateWrapper<>();
        rollback.eq(TIndexRecord::getIsActive, ActiveType.DEAD.value)
                .orderByDesc(TIndexRecord::getCreateTime)
                .last("limit 1")
                .set(TIndexRecord::getIsActive, ActiveType.ALIVE.value)
                .set(TIndexRecord::getRemark, indexRecord.getRemark()+"回滚时间:"+ LocalDateTimeUtils.nowFormatted() +"回滚旧索引:"+indexRecord.getIndexName()+"\n");
        updateWrapper.eq(TIndexRecord::getId, indexRecord.getId())
                .set(TIndexRecord::getIsActive, ActiveType.DEAD.value);
        rollbackInfo.setOldIndex(indexRecord.getIndexName());
        // 是否存在可回滚的索引
        if(tIndexRecordMapper.update(rollback)==0){
            // 记录索引回滚失败
            updateWrapper.set(TIndexRecord::getRemark, indexRecord.getRemark()+"回滚时间:"+LocalDateTimeUtils.nowFormatted()+"被回滚失败"+"\n");
            // 将当前损坏的索引标记死亡
            tIndexRecordMapper.update(updateWrapper);
            rollbackInfo.setSwitchFlag(SwitchFlag.FAILURE);
            return rollbackInfo;
        }
        updateWrapper.set(TIndexRecord::getRemark, indexRecord.getRemark()+"回滚时间:"+LocalDateTimeUtils.nowFormatted()+"被回滚"+"\n")
                .set(TIndexRecord::getDeleted,1);
        tIndexRecordMapper.update(updateWrapper);
        indexRecord = tIndexRecordMapper.selectOne(queryWrapper);
        rollbackInfo.setNewIndex(indexRecord.getIndexName());
        postIndexManager.rollBackIndex(rollbackInfo.getOldIndex(), rollbackInfo.getNewIndex());
        rollbackInfo.setSwitchFlag(SwitchFlag.SUCCESS);
        return rollbackInfo;
    }

    @Override
    public PageResult<IndexRecordVo> findAll(Integer pageNum, Integer pageSize) {
        LambdaQueryWrapper<TIndexRecord> queryWrapper = new LambdaQueryWrapper<>();
        Page<TIndexRecord> page = tIndexRecordMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper);
        return new PageResult<>(page.getTotal(), page.getRecords().stream().map(this::convert).toList());
    }

    @Override
    public List<String> findNotActive() {
        LambdaQueryWrapper<TIndexRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TIndexRecord::getIsActive, ActiveType.DEAD.value)
                .orderByDesc(TIndexRecord::getCreateTime)
                .select(TIndexRecord::getId)
                .last("limit 1");
        TIndexRecord indexRecord = tIndexRecordMapper.selectOne(queryWrapper);
        if(ObjectUtils.isEmpty(indexRecord)){
            return Collections.emptyList();
        }
        LambdaQueryWrapper<TIndexRecord> q = new LambdaQueryWrapper<>();
        q.eq(TIndexRecord::getIsActive, ActiveType.DEAD.value)
                .ne(TIndexRecord::getId, indexRecord.getId());
        return tIndexRecordMapper.selectList(q).stream().map(TIndexRecord::getIndexName).toList();
    }

    private IndexRecordVo convert(TIndexRecord record){
        IndexRecordVo vo = new IndexRecordVo();
        BeanUtils.copyProperties(record, vo);
        return vo;
    }

}
